#include "mainstaticgesturedialog.h"
#include "ui_mainstaticgesturedialog.h"

#include "trainstaticgesturedialog.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QMap>
#include <QTemporaryFile>

#include <cv.h>
#include <cfloat>

#include <mlgesture.h>
#include <svm.h>

using namespace std;
using namespace cv;
using namespace mlgesture;

MainStaticGestureDialog::MainStaticGestureDialog(QWidget *parent) :
    QDialog(parent),
    ui_(new Ui::mainStaticGestureDialog)
{

	printf("%lf", 0.12321);
    ui_->setupUi(this);
	connect(ui_->addDataButton, SIGNAL(clicked()), this, SLOT(addData()));
	connect(ui_->dataFileButton, SIGNAL(clicked()), this, SLOT(selectDataFile()));
}

MainStaticGestureDialog::~MainStaticGestureDialog()
{
    delete ui_;
}

void MainStaticGestureDialog::addData() {
	TrainStaticGestureDialog *dialog = new TrainStaticGestureDialog(this);
	dialog->show();
}

void MainStaticGestureDialog::selectDataFile() {
	dataFile_ = QFileDialog::getOpenFileName(this, tr("Wybierz plik z danymi"), QDir::currentPath(), QString(), 0,
											  QFileDialog::DontConfirmOverwrite);
	ui_->dataFileEdit->setText(dataFile_.trimmed());
}

void MainStaticGestureDialog::accept() {
	if (dataFile_.trimmed().isEmpty()) {
		QMessageBox::warning(this, tr("Brak pliku z danymi"), tr("Nie wybrano pliku z danymi"));
	}
	else {
		svm_parameter param;
		svm_problem prob;
		svm_model *model;

		//set libsvmparams
		param.svm_type = C_SVC;
		param.kernel_type = RBF;
		param.degree = 3;
		param.gamma = 1.0/7;
		if (!ui_->svmGEdit->text().trimmed().isEmpty()) {
			bool ok;
			double tmp = ui_->svmGEdit->text().trimmed().toDouble(&ok);
			if (ok) {
				param.gamma = tmp;
			}
		}
		param.coef0 = 0;
		param.nu = 0.5;
		param.cache_size = 100;
		param.C = 1;
		if (!ui_->svmCEdit->text().trimmed().isEmpty()) {
			bool ok;
			double tmp = ui_->svmCEdit->text().trimmed().toDouble(&ok);
			if (ok) {
				param.C = tmp;
			}
		}
		param.eps = 1e-3;
		param.p = 0.1;
		param.shrinking = 1;
		param.probability = 1;
		param.nr_weight = 0;
		param.weight_label = NULL;
		param.weight = NULL;

		QFile data_qfile(dataFile_);
		data_qfile.open(QIODevice::ReadOnly | QIODevice::Text);
		if (!data_qfile.isOpen())
			throw HandGestureException(("Cannot open " + dataFile_ + " file").toStdString());

		QTemporaryFile svm_tmp_file;
		QTextStream in_data(&data_qfile);

		prob.l=0;
		vector<vector<double> > data;
		QString line = in_data.readLine();
		while (!line.isNull()) {
			QStringList list = line.split(" ");
			if (list.size() != 8) {
				throw HandGestureException("Data file has bad structure");
			}
			prob.l++;
			line = in_data.readLine();
		}
		data.resize(prob.l);
		in_data.seek(0);
		line = in_data.readLine();
		int line_num = 0;
		while (!line.isNull()) {
			QStringList list = line.split(" ");
			data[line_num].push_back(list[0].toInt());
			for (int i=0; i<7; i++) {
				QStringList list2 = list[i+1].split(":");
				if (list2.size() != 2) {
					throw HandGestureException("Data file has bad structure");
				}
				data[line_num].push_back(list2[1].toDouble());
			}
			line_num++;
			line = in_data.readLine();
		}
		data_qfile.close();

		scaleData(data, dataFile_ + ".scale", dataFile_ + ".scale_factors");
		data_qfile.setFileName(dataFile_ + ".scale");
		data_qfile.open(QIODevice::ReadOnly | QIODevice::Text);
		in_data.setDevice(&data_qfile);

		prob.l = prob.l;
		prob.y = new double[prob.l];
		prob.x = new svm_node*[prob.l];
		in_data.seek(0);
		line_num = 0;
		line = in_data.readLine();
		while (!line.isNull()) {
		QStringList list = line.split(" ");
		prob.y[line_num] = list[0].toInt();
		prob.x[line_num] = new svm_node[8];
		for (int i=0; i<7; i++) {
				QStringList list2 = list[i+1].split(":");
				prob.x[line_num][i].index = i+1;
				prob.x[line_num][i].value = list2[1].toDouble();
			}
			prob.x[line_num][7].index = -1;
			line_num++;
			line = in_data.readLine();
		}
		data_qfile.close();

		svm_tmp_file.open();
		svm_tmp_file.close();
		model = svm_train(&prob, &param);
		svm_save_model(svm_tmp_file.fileName().toAscii(), model);
		svm_free_model_content(model);

		if (QFile::exists(dataFile_ + ".model")) {
			QFile::remove(dataFile_ + ".model");
		}
		QFile::copy(svm_tmp_file.fileName(), dataFile_ + ".model");

		for (int i=0; i<prob.l; i++) {
			delete [] prob.x[i];
		}
		delete [] prob.x;
		delete [] prob.y;

		svm_tmp_file.close();

		QDialog::accept();
	}
}

void MainStaticGestureDialog::scaleData(const vector<vector<double> > &data, const QString &result_file,
										const QString &factors_file) const {
	double min_val[7];
	double max_val[7];

	for (int i=0; i<7; i++) {
		min_val[i] = DBL_MAX;
		max_val[i] = DBL_MIN;
	}
	for (vector<vector<double> >::const_iterator it = data.begin(); it != data.end(); ++it) {
		for (int i=0; i<7; i++) {
			if ((*it)[i+1] < min_val[i])
				min_val[i] = (*it)[i+1];
			if ((*it)[i+1] > max_val[i])
				max_val[i] = (*it)[i+1];
		}
	}

	QFile factors(factors_file);
	factors.open(QIODevice::WriteOnly | QIODevice::Text);
	if (!factors.isOpen())
		throw HandGestureException(("Cannot open " + factors_file + " file").toStdString());
	QTextStream out_factors(&factors);
	for (int i=0; i<7; i++) {
		out_factors << min_val[i] << " " << max_val[i] << endl;
	}
	factors.close();

	QFile data_dile(result_file);
	data_dile.open(QIODevice::WriteOnly | QIODevice::Text);
	if (!data_dile.isOpen())
		throw HandGestureException(("Cannot open " + result_file + " file").toStdString());

	QTextStream out_data(&data_dile);
	for (vector<vector<double> >::const_iterator it = data.begin(); it != data.end(); ++it) {
		int tmp = (int)(*it)[0];
		out_data << tmp;
		for (int i=1; i<=7; i++) {
			out_data << " " << i << ":";
			double tmpVal = -1 + 2*((*it)[i] - min_val[i-1])/(max_val[i-1] - min_val[i-1]);
			out_data << tmpVal;
		}
		out_data << endl;
	}
	data_dile.close();
}
